package com.shitou.shitoumember.service.impl;

import com.alibaba.fastjson.JSON;
import com.shitou.shitoucommons.exception.RRException;
import com.shitou.shitoucommons.utils.*;
import com.shitou.shitoucommons.validate.MemberEnum;
import com.shitou.shitoucommons.vo.MemberVo;
import com.shitou.shitoumember.entity.*;
import com.shitou.shitoumember.service.*;
import com.shitou.shitoumember.utils.IPToCityUtils;
import com.shitou.shitoumember.utils.IPUtils;
import com.shitou.shitoumember.utils.MemberContext;
import com.shitou.shitoumember.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.shitou.shitoumember.dao.MemberDao;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@Slf4j
@SuppressWarnings("all")
@Transactional
@Service("memberService")
public class MemberServiceImpl extends ServiceImpl<MemberDao, MemberEntity> implements MemberService {

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<MemberEntity> page = this.page(
                new Query<MemberEntity>().getPage(params),
                new QueryWrapper<MemberEntity>()
        );

        return new PageUtils(page);
    }


    @Autowired
    private CaptchaService captchaService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private MemberLevelService memberLevelService;
    @Autowired
    private MemberLoginLogService memberLoginLogService;
    @Autowired
    private MemberStatisticsInfoServiceImpl memberStatisticsInfoService;
    @Autowired
    @Qualifier("RedisTemplate")
    private RedisTemplate redisTemplate;



    @Override
    public RespBean doLogin(LoginVo loginVo, HttpServletRequest request, HttpServletResponse response){
        return doLogin(loginVo, request,response,  true);
    }


    /**
     * 登录
     * @param loginVo 用户信息
     * @return
     */
    @Override
    public RespBean doLogin(LoginVo loginVo, HttpServletRequest request, HttpServletResponse response, boolean checkCaptcha) {
        // 验证码校验
        if( checkCaptcha ){
            boolean captchaBool = captchaService.validate(loginVo.getUuid(), loginVo.getCaptcha());
            if ( !captchaBool ){
                return RespBean.error("uuid异常");
            }
        }

        // 从数据库中获取数据
        MemberEntity memberDo = this.getOne(
                new QueryWrapper<MemberEntity>()
                        .eq("account", loginVo.getAccount()));
        // 账号不存在或者密码不正确
        if ( memberDo == null ){
            return RespBean.error(MemberEnum.LOGIN_ERROR.getCode(), MemberEnum.LOGIN_ERROR.getMessage());
        }
        String inputPassword = String.valueOf(new Sha256Hash(loginVo.getPassword(), memberDo.getSalt()));
        if (  !memberDo.getPassword().equals(inputPassword) ) {
            return RespBean.error(MemberEnum.LOGIN_ERROR.getCode(), MemberEnum.LOGIN_ERROR.getMessage());
        }

        // 账号被锁定，联系管理员
        if ( memberDo.getStatus() == 0 ){
            return RespBean.error(MemberEnum.STATUS_ERROR.getCode(), MemberEnum.STATUS_ERROR.getMessage());
        }

        // 建立此次登录日志，并关联会员member
        MemberLoginLogEntity umsMemberLoginLog = new MemberLoginLogEntity();
        umsMemberLoginLog.setMemberId(memberDo.getId()); // 设置会员id
        umsMemberLoginLog.setCreateTime(new Date()); // 设置创建时间
        umsMemberLoginLog.setLoginType(1);   // 设置登录类型-默认是web
        String ip = IPUtils.getIpAddr(request);
        if ( ip.equals("0:0:0:0:0:0:0:1")) ip = "127.0.0.1";
        umsMemberLoginLog.setIp(ip);  // 设置ip

        // 获取城市
        String city = IPToCityUtils.iPToCityUtils(ip);
//        if (!ip.equals("127.0.0.1")) {
//            int i = city.indexOf("-");
//            if ( i != -1){
//                city = city.substring(i+1, city.length());
//            }
//            i = city.indexOf("-");
//            if (i != -1) {
//                city = city.substring(0, i);
//            }
//        }
        umsMemberLoginLog.setCity(city);  // 设置城市
        memberLoginLogService.save(umsMemberLoginLog);

        // 生成token
        RespBean respBean = tokenService.createToken(memberDo.getId());

        // 登录成功，将用户存入threadLocal中
        MemberContext.setObject(memberDo);
        String token = (String) respBean.get("token");

        String jsonString = JSON.toJSONString(memberDo);
        /**
         * 每个用户登陆时效半个小时，如果期间没有进行操作，那么则需要重新登录
         */
        redisTemplate.opsForValue().set("member:" + token, jsonString,60 * 30, TimeUnit.SECONDS);
        Cookie cookie = new Cookie("memberTicket", token);
        cookie.setPath("/");
        cookie.setMaxAge(60 * 32);
        response.addCookie(cookie);

        MemberStatisticsInfoEntity memberStatisticsInfo = memberStatisticsInfoService.getOne(
                new QueryWrapper<MemberStatisticsInfoEntity>().eq("member_id", memberDo.getId()));
        if( memberStatisticsInfo == null ){
            throw new RRException("获取用户信息失败");
        }
        memberStatisticsInfo.setLoginCount(memberStatisticsInfo.getLoginCount() + 1);
        memberStatisticsInfoService.updateById(memberStatisticsInfo);

        return respBean;
    }


    @Override
    public RespBean doRegister(RegisterVo registerVo){
        return doRegister(registerVo, true);
    }


    /**
     * 注册操作
     * @param registerVo
     * @return
     */
    @Override
    public RespBean doRegister(RegisterVo registerVo, boolean checkCaptcha) {

        // 验证数据是否合规
//        String param = registerVo.getAccount() + registerVo.getPassword();
//        CensorVo censorVo = TextCensor.TextCensor(param);
//        if (censorVo.getConclusion().equals("不合规") || censorVo.getConclusionType().equals("2")){
//            throw new RRException("输入信息不合法,内有违规信息");
//        }


        if ( checkCaptcha ){
            boolean validate = captchaService.validate(registerVo.getUuid(), registerVo.getCaptcha());
            if ( !validate ){
                throw new RuntimeException("验证码错误");
            }
        }

        // 判断该账号是否已经注册
        MemberEntity account = this.getOne(new QueryWrapper<MemberEntity>().eq("account", registerVo.getAccount()));
        if ( !(account == null) ){
            throw new RRException("该账户已经被注册了");
        }

        // 判断该邮箱是否被注册
        MemberEntity umsMemberEmail = this.getOne(new QueryWrapper<MemberEntity>().eq("email", registerVo.getEmail()));
        if ( !(umsMemberEmail == null) ){
            throw new RRException("该邮箱已经被注册了");
        }

        // 保存member数据库
        MemberEntity umsMember = new MemberEntity();
        umsMember.setEmail(registerVo.getEmail());  // 邮箱
        umsMember.setAccount(registerVo.getAccount()); // 账号
        String salt = TokenGenerator.generatorValue();
        umsMember.setPassword(String.valueOf(new Sha256Hash(registerVo.getPassword(), salt))); // 密码
        umsMember.setSalt(salt);  // 盐
        umsMember.setStatus(1);  // 状态
        umsMember.setJob("其它"); // 职业
        umsMember.setCreateTime(new Date());  // 创建时间
        umsMember.setSign("这个人很懒，什么都没有留下");  // 个性签名
        umsMember.setNickname(TokenGenerator.generatorValue().substring(0,8)); // 设置会员名称
        // 创建并保存用户
        this.save(umsMember);
        MemberEntity umsMemberDo = this.getOne(
                new QueryWrapper<MemberEntity>().eq("account", umsMember.getAccount()));

        // 创建会员等级并关联用户
        MemberLevelEntity umsMemberLevel = new MemberLevelEntity();
        umsMemberLevel.setMemberId(umsMemberDo.getId());  // 关联用户id
        umsMemberLevel.setCommentGrowthPoint(1);  // 设置每次评价的成长值
        umsMemberLevel.setDefaultStatus(0);   // 设置是否为默认等级，否0
        umsMemberLevel.setGrowthPoint(1);  //  设置初始成长值
        umsMemberLevel.setName("VIP-1");   // 设置名称，VIP-1 ~ VIP-8
        umsMemberLevel.setPriviledgeFreeFreight(0);   // 设置是否有免邮特权
        umsMemberLevel.setNote("当前您的会员等级为: VIP-1 | 没有特权哦");  // 对会员等级的描述
        memberLevelService.save(umsMemberLevel);
        MemberLevelEntity umsMemberLevelDo = memberLevelService.getOne(
                new QueryWrapper<MemberLevelEntity>().eq("member_id", umsMemberDo.getId()));
        // 用户关联会员等级
        umsMemberDo.setLevelId(umsMemberLevelDo.getId());
        this.updateById(umsMemberDo);  // 更新数据用户关联


        // 创建会员的信息统计
        MemberStatisticsInfoEntity statisticsInfo = new MemberStatisticsInfoEntity();
        statisticsInfo.setMemberId(umsMemberDo.getId());  // 设置会员id进行关联
        statisticsInfo.setCollectProductCount(0);   // 设置会员收藏商品数量
        statisticsInfo.setCommentCount(0);     // 设置会员评论数
        statisticsInfo.setConsumeAmount(BigDecimal.valueOf(0.0));   // 设置会员消费金额
        statisticsInfo.setEarnAmount(BigDecimal.valueOf(0.0));    // 设置会员累计赚取金额
        statisticsInfo.setLoginCount(0);    // 设置会员登录次数
        statisticsInfo.setOrderCount(0);   // 设置会员的订单总数
        statisticsInfo.setReturnOrderCount(0);   // 设置会员的退货数量
        memberStatisticsInfoService.save(statisticsInfo);   // 保存

        return RespBean.success().put("id", umsMemberDo.getId());
    }


    /**
     * 登出
     * @param memberId
     * @return
     */
    @Override
    public RespBean doLoginOut(long memberId) {
        return tokenService.loginOut(memberId);
    }


    /**
     * 获取用户的信息 接口
     * @param memberInfoVo
     * @return
     */
    @Override
    public RespBean memberInfo(HttpServletRequest request, HttpServletResponse response) {
        Cookie[] cookies = request.getCookies();
        String token = null;
        if ( cookies == null ) {
            return RespBean.error(402, "用户未登录，token异常");
        }
        for (Cookie cookie : cookies) {
            if ( cookie.getName().equals("memberTicket") ){
                token = cookie.getValue();
                break;
            }
        }
        if (token == null || token.equals("")) {
            return RespBean.error(402, "用户未登录，token异常");
        }
        // 查询token是否过期
        TokenEntity umsToken = tokenService.checkTokenTime(token, null);
        if( umsToken == null ) {
            return RespBean.error(402, "用户登陆过期，或者越权操作");
        }
        // 查询用户信息
        MemberEntity umsMemberDo = this.getOne(new QueryWrapper<MemberEntity>().eq("id", umsToken.getMemberId()));
        if ( umsMemberDo == null ){
            return RespBean.error(402, "用户信息错误,或未登录");
        }

        // 获取会员等级信息
        MemberLevelEntity umsMemberLevelDo = memberLevelService.getOne(
                new QueryWrapper<MemberLevelEntity>().eq("id", umsMemberDo.getLevelId()).eq("member_id", umsMemberDo.getId()));
        // 获取用户登录日志
        List<MemberLoginLogEntity> list = memberLoginLogService.list(new QueryWrapper<MemberLoginLogEntity>().eq("member_id", umsMemberDo.getId()));

        if ( umsMemberLevelDo == null ){
            return RespBean.error("会员等级信息出错，请联系管理员");
        }
        MemberInfoVo memberInfoVo = new MemberInfoVo();

        memberInfoVo.setAccount(umsMemberDo.getAccount());  // 设置账号
        memberInfoVo.setHeader(umsMemberDo.getHeader());   // 用户头像
        memberInfoVo.setNickname(umsMemberDo.getNickname()); // 会员名称
        memberInfoVo.setLevel(umsMemberLevelDo.getName());  // 等级名称
        memberInfoVo.setNote(umsMemberLevelDo.getNote());   // 会员等级描述
        memberInfoVo.setMobile(umsMemberDo.getMobile());  // 会员电话号码
        memberInfoVo.setEmail(umsMemberDo.getEmail());  // 会员邮箱
        memberInfoVo.setGender(umsMemberDo.getGender());  // 会员年龄
        memberInfoVo.setId(umsMemberDo.getId());   // 设置id

        String city = list.get(list.size() - 1).getCity();
        String ip = list.get(list.size() - 1).getIp();
        if (!ip.equals("127.0.0.1")) {
            int i = city.indexOf("-");
            if ( i != -1){
                city = city.substring(i+1, city.length());
            }
            i = city.indexOf("-");
            if (i != -1) {
                city = city.substring(0, i);
            }
        }
        memberInfoVo.setCity(city);  // 设置城市

        // TODO 数据脱敏


        // 从新设置登陆时长两年半
        Cookie cookie = new Cookie("memberTicket", token);
        cookie.setPath("/");
        cookie.setMaxAge(60 * 32);
        response.addCookie(cookie);

        String jsonString = JSON.toJSONString(umsMemberDo);
        redisTemplate.opsForValue().set("member:" + token, jsonString,60 * 30, TimeUnit.SECONDS);

        // 后续添加...
        return RespBean.success().put("data", memberInfoVo);
    }


    /**
     * 更新nickneme 和 gender
     * @param nicknameGenderVo
     * @return
     */
    @Override
    public RespBean updateNicknameGender(UpdateNicknameGenderVo nicknameGenderVo) {

        // 校验用户名是否合法
        CensorVo censorVo = TextCensor.TextCensor(nicknameGenderVo.getNickname());
        if (censorVo.getConclusion().equals("不合规") || censorVo.getConclusionType().equals("2")){
            throw new RRException("输入信息不合法,内有违规信息");
        }


        int id = nicknameGenderVo.getId();
        MemberEntity umsMemberDo = this.getOne(new QueryWrapper<MemberEntity>().eq("id", id));
        if ( umsMemberDo == null ){
            throw new RRException("更新名称或性别失败");
        }
        umsMemberDo.setNickname(nicknameGenderVo.getNickname());
        umsMemberDo.setGender(nicknameGenderVo.getGender());
        this.updateById(umsMemberDo);
        return RespBean.success();
    }


    /**
     * 更新头像
     * @param headerVo
     * @return
     */
    @Override
    public RespBean updateHeader(UpdateHeaderVo headerVo) {
        int id = headerVo.getId();
        MemberEntity umsMemberDo = this.getOne(new QueryWrapper<MemberEntity>().eq("id", id));
        if ( umsMemberDo == null ){
            throw new RRException("更新头像失败");
        }
        umsMemberDo.setHeader(headerVo.getHeader());
        this.updateById(umsMemberDo);
        return RespBean.success();
    }


    /**
     * 更新邮箱
     * @param emailVo
     * @return
     */
    @Override
    public RespBean updateEmail(UpdateEmailVo emailVo) {
        // 获得用户信息
        MemberEntity umsMemberDo = this.getOne(new QueryWrapper<MemberEntity>().eq("id", emailVo.getId())
                .eq("email", emailVo.getOldEmail()));

        if ( umsMemberDo == null ){
            throw new RRException("更新失败");
        }
        umsMemberDo.setEmail(emailVo.getNewEmail());
        this.updateById(umsMemberDo);
        return RespBean.success();
    }


    /**
     * 找回密码
     * @param passwordVo
     * @return
     */
    @Override
    public RespBean findPassword(UpdatePasswordVo passwordVo) {
        MemberEntity umsMemberDo = this.getOne(new QueryWrapper<MemberEntity>()
                .eq("email", passwordVo.getEmail()));
        if ( umsMemberDo == null ){
            throw new RRException("密码更新失败");
        }
        umsMemberDo.setPassword(String.valueOf(new Sha256Hash(passwordVo.getNewPassword(), umsMemberDo.getSalt())));

        this.updateById(umsMemberDo);
        return RespBean.success();
    }


    /**
     * 远程调用，获取用户的信息
     * @param memberId
     * @return
     */
    @Override
    public RespBean getMemberVo(long memberId, HttpServletRequest request, HttpServletResponse response) {

        MemberVo memberVo = new MemberVo();
        MemberEntity memberDo = this.getOne(new QueryWrapper<MemberEntity>().eq("id", memberId));
        if ( memberDo == null ){
            throw new RRException("用户获取失败");
        }
        memberVo.setUsername(memberDo.getNickname());
        String jsonString = JSON.toJSONString(memberVo);
        return RespBean.success().put("data", jsonString);
    }


    /**
     * 远程调用，判断是否登录
     * @param request
     * @param response
     * @return true or false
     */
    @Override
    public RespBean checkLogin(String token,HttpServletResponse response) {

        TokenEntity tokenEntity = getTokenEntityByToken(token, response);

        if ( tokenEntity == null ){
            return RespBean.error().put("data", "false");
        }

        return RespBean.success().put("data", "true");
    }


    private TokenEntity getTokenEntityByToken(String token, HttpServletResponse response){
        MemberEntity member = JSON.parseObject((String) redisTemplate.opsForValue().get("member:" + token), MemberEntity.class);
        if (member == null) {
            log.info("member is null for token: " + token);
            return null;
        }
        // 判断时间是否过期
        TokenEntity tokenEntity = tokenService.checkTokenTime(token, response);

        return tokenEntity;
    }


    /**
     * 通过用户的id获取用户的信息
     * @param memberIds
     * @return
     */
    @Override
    public RespBean getMemberInfoByMemberIds(long[] memberIds) {
        AllMemberVo allMemberVo = null;
        List<AllMemberVo> list = new ArrayList<>();
        for (long memberId : memberIds) {
            MemberEntity member = this.getOne(new QueryWrapper<MemberEntity>().eq("id", memberId));
            allMemberVo = new AllMemberVo();
            allMemberVo.setMemberId(memberId);
            allMemberVo.setNickname(member.getNickname());
            allMemberVo.setHeader(member.getHeader());
            list.add(allMemberVo);
        }
        return RespBean.success().put("data", list);
    }


    /**
     * 通过token获取用户
     * @param token 令牌
     * @param request
     * @param response
     * @return
     */
    @Override
    public MemberEntity getMemberByToken(String token, HttpServletRequest request, HttpServletResponse response) {
        if ( token == null || token.equals("") ){
            return null;
        }
        MemberEntity member = JSON.parseObject((String) redisTemplate.opsForValue().get("member:" + token), MemberEntity.class);
        Cookie cookie = null;
        // 用户为空，清除cookie
        if ( member == null ){
            cookie = new Cookie("memberTicket", "");
            cookie.setMaxAge(0);
            cookie.setPath("/");
            response.addCookie(cookie);
            return null;
        }
        cookie = new Cookie("memberTicket", token);
        cookie.setPath("/");
        cookie.setMaxAge(60 * 32);
        response.addCookie(cookie);

        // 每次访问的时候都会重新设置时间为半个个小时
        String jsonString = JSON.toJSONString(member);
        redisTemplate.opsForValue().set("member:" + token, jsonString,60 * 30, TimeUnit.SECONDS);

        return member;
    }


    /**
     * 前端调用，校验该页面是否要需要登陆才能访问
     * @param request
     * @return
     */
    @Override
    public RespBean fore_endCheckLogin(HttpServletRequest request, HttpServletResponse response) {
        Cookie[] cookies = request.getCookies();
        String token = Arrays.stream(cookies).filter(cookie -> cookie.getName().equals("memberTicket"))
                .findFirst()
                .map(Cookie::getValue)
                .orElse("");
        TokenEntity tokenEntity = getTokenEntityByToken(token, response);
        MemberEntity id = this.getOne(new QueryWrapper<MemberEntity>().eq("id", tokenEntity.getMemberId()));
        String jsonString = JSON.toJSONString(id);
        if (tokenEntity == null){
            return RespBean.error(402, "用户未登录");
        }
        redisTemplate.opsForValue().set("member:" + token, jsonString,60 * 30, TimeUnit.SECONDS);
        return RespBean.success();
    }


    /**
     * 获取商品发布者的信息
     * @param memberId
     * @return
     */
    @Override
    public RespBean getPublisher(Long memberId) {
        MemberEntity member = this.getOne(new QueryWrapper<MemberEntity>().eq("id", memberId).eq("status", 1));
        if ( member == null ){
            throw new RRException("该用户已经注销");
        }
        PublisherVo publisherVo = new PublisherVo();
        publisherVo.setNickname(member.getNickname());
        publisherVo.setHeader(member.getHeader());
        publisherVo.setSign(member.getSign());

        TokenEntity tokenEntity = tokenService.getOne(new QueryWrapper<TokenEntity>().eq("member_id", memberId));
        String token = null;
        String jsonString = null;
        if ( tokenEntity != null ){
            token = tokenEntity.getToken();
            Date expireTime = tokenEntity.getExpireTime();
            publisherVo.setLastLoginTime(expireTime);
            jsonString = (String) redisTemplate.opsForValue().get("member:" + token);
        }else {
            publisherVo.setLastLoginTime(new Date());
        }

        if ( jsonString == null || jsonString.equals("") ){
            publisherVo.setOnline(false);
        }else {
            publisherVo.setOnline(true);
        }

        String city = "未知IP";
        List<MemberLoginLogEntity> loginLogList = memberLoginLogService.list(new QueryWrapper<MemberLoginLogEntity>().eq("member_id", memberId));
        if ( loginLogList.size() > 0 ){
            MemberLoginLogEntity memberLoginLogEntity = loginLogList.get(loginLogList.size() - 1);
            city = memberLoginLogEntity.getCity();
        }
        publisherVo.setCity(city);
        return RespBean.success().put("data", publisherVo);
    }


    /**
     * 通过会员id获取会员信息
     * @param MemberId
     * @return
     */
    @Override
    public RespBean getMemberByMemberId(Long memberId) {

        MemberEntity umsMemberDo = this.getOne(new QueryWrapper<MemberEntity>().eq("id", memberId));

        // 获取会员等级信息
        MemberLevelEntity umsMemberLevelDo = memberLevelService.getOne(
                new QueryWrapper<MemberLevelEntity>().eq("id", umsMemberDo.getLevelId()).eq("member_id", umsMemberDo.getId()));
        // 获取用户登录日志
        List<MemberLoginLogEntity> list = memberLoginLogService.list(new QueryWrapper<MemberLoginLogEntity>().eq("member_id", umsMemberDo.getId()));

        if ( umsMemberLevelDo == null ){
            return RespBean.error("会员等级信息出错，请联系管理员");
        }
        MemberInfoVo memberInfoVo = new MemberInfoVo();

        memberInfoVo.setAccount(umsMemberDo.getAccount());  // 设置账号
        memberInfoVo.setHeader(umsMemberDo.getHeader());   // 用户头像
        memberInfoVo.setNickname(umsMemberDo.getNickname()); // 会员名称
        memberInfoVo.setLevel(umsMemberLevelDo.getName());  // 等级名称
        memberInfoVo.setNote(umsMemberLevelDo.getNote());   // 会员等级描述
        memberInfoVo.setMobile(umsMemberDo.getMobile());  // 会员电话号码
        memberInfoVo.setEmail(umsMemberDo.getEmail());  // 会员邮箱
        memberInfoVo.setGender(umsMemberDo.getGender());  // 会员年龄
        memberInfoVo.setId(umsMemberDo.getId());   // 设置id
        memberInfoVo.setCity(list.get(list.size() - 1).getCity());  // 设置城市

        // 设置在线
        TokenEntity token = tokenService.getOne(new QueryWrapper<TokenEntity>().eq("member_id", memberId));
        Object o = redisTemplate.opsForValue().get("member:" + token.getToken());
        if ( o != null ){
            memberInfoVo.setOnline(true);
        }else {
            memberInfoVo.setOnline(false);
        }

        return RespBean.success().put("data", memberInfoVo);
    }

}
